home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-05-05 | 17.6 KB | 573 lines | [TEXT/ALFA] |
- ####################################################################
- #
- # Much by Vince Darley.
- #
- # created: 26/11/96 {7:08:34 pm}
- # last update: 05/05/1999 {18:20:37 PM}
- # Author: Vince Darley
- # E-mail: <darley@fas.harvard.edu>
- # mail: Division of Applied Sciences, Harvard University
- # Oxford Street, Cambridge MA 02138, USA
- # www: <http://www.fas.harvard.edu/~darley/>
- #
- ####################################################################
-
- ##
- # Here's a brief explanation of the smart fillParagraph routines
- #
- # 'fillParagraph'
- #
- # If there's a selection, then fill all paragraphs in that selection. If
- # not then fill the paragraph surrounding the insertion point. The
- # definition of a 'paragraph' may be mode dependent (see paraStart,
- # paraFinish)
- #
- # 'fillOneParagraph'
- #
- # Fills the single paragraph surrounding the insertion point. If called
- # with parameter '0', it doesn't bother to remember where the insertion
- # point was, which makes multiple paragraph fills quicker when called by
- # 'fillParagraph'. Works for mode-dependent definitions of paragraphs and
- # for commented out text (such as this paragraph here!).
- #
- # 'rememberWhereYouAre'
- #
- # Given the start of a paragraph and the point to remember, this returns a
- # record which must be passed to the following function so that it can
- # find the spot later, even after the paragraph has had
- # space/tabs/new-lines meddled with. An optional last argument is a list
- # of other characters quoted so they are regexp insensitive, which should
- # also be ignored. This is used so we can remember positions in text
- # which has cosmetic characters on the left/right which are not wrapped
- # (such as the hashes to the left here!).
- #
- # 'goBackToWhereYouWere'
- #
- # Given the beginning and end of a selection, and a previous record, where
- # the beginning, and record correspond to a previous call of
- # 'rememberWhereYouAre', this procedure will move the insertion point to
- # the correct place.
- #
- # 'paraStart'
- #
- # Finds the start of the paragraph containing the insertion point.
- #
- # 'paraFinish'
- #
- # Finds the end of the paragraph containing the insertion point.
- ##
-
- proc fillParagraph {} {
- if {[pos::compare [getPos] == [selEnd]]} {
- fillOneParagraph
- } else {
- set start [getPos]
- set end [selEnd]
- set p $start
- while {[pos::compare $p < $end] && [pos::compare $p < [maxPos]]} {
- goto $p
- set p [fillOneParagraph 0 $start $end]
- }
- goto $start
- }
- }
-
- proc rememberWhereYouAre {startPara pos endPara {commentReg ""}} {
- set start [pos::math $pos -20]
- if {[pos::compare $start < $startPara]} {
- set start $startPara
- }
- set __g_remember_str [getText $start $pos]
- if {[string length [string trim $__g_remember_str]] < 3} {
- # there wasn't much to remember; try the other way
- set end [pos::math $pos +20]
- if {[pos::compare $end > $endPara]} {
- set end $endPara
- }
- set __g_remember_str [getText $pos $end]
- set __g_remember_dir 0
- } else {
- set __g_remember_dir 1
- }
-
- set __g_remember_str [quote::Regfind $__g_remember_str]
- regsub -all "\[ \t\r\n${commentReg}\]+" $__g_remember_str \
- {[ \t\r\n${commentReg}]+} __g_remember_str
- return [list $__g_remember_str $__g_remember_dir]
- }
-
- proc goBackToWhereYouWere {start end memory} {
- if {[lindex $memory 0] != "" } {
- regexp -indices ".*([lindex $memory 0]).*" [getText $start $end] \
- "" submatch
- if {[info exists submatch]} {
- set p [pos::math $start + [lindex $memory 1] + \
- [lindex $submatch [lindex $memory 1]]]
- } else {
- set p $end
- }
- goto [expr {[pos::compare $p >= $end] ? [pos::math $end - 1] : $p}]
- } else {
- goto $start
- }
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "getLeadingIndent" --
- #
- # Find the indentation of the line containing 'pos', and convert it to a
- # minimal form of tabs followed by spaces. If 'size' is given, then the
- # variable of that name is set to the length of the indent. Similarly
- # 'halftab' can be set to half a tab.
- # -------------------------------------------------------------------------
- ##
- proc getLeadingIndent { pos {size ""} {halftab ""} } {
- # get the leading whitespace of the current line
- set res [search -s -n -f 1 -r 1 "^\[ \t\]*" [lineStart $pos]]
-
- # convert it to minimal form: tabs then spaces, stored in 'front'
- getWinInfo a
- set sp [string range " " 1 $a(tabsize) ]
- regsub -all "($sp| +\t)" [eval getText $res] "\t" front
- if { $size != "" } {
- upvar $size ind
- # get the length of the indent
- regsub -all "\t" $front $sp lfront
- set ind [string length $lfront]
- }
- if { $halftab != "" } {
- upvar $halftab ht
- # get the length of half a tab
- set ht [string range " " 1 [expr {$a(tabsize)/2}]]
- }
-
- return $front
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "fillOneParagraph" --
- #
- # Fixes: won't put a double-space after abbreviations like 'e.g.', 'i.e.'
- #
- # Works around the Alpha 'replaceText' bug.
- # -------------------------------------------------------------------------
- ##
- proc fillOneParagraph {{remember 1} {minstart ""} {maxend ""}} {
- global leftFillColumn fillColumn doubleSpaces
-
- set pos [getPos]
- if {[set inComment [text::isInComment $pos ch]]} {
- # Find lines which contain just a comment char, but no actual text
- # (We want to flow the text in the comment in its constituent
- # paragraphs, not as one big block).
- set ch [string trim $ch]
- set chreg [quote::Regfind ${ch}]
- if {$ch == "*"} {
- # We assume it's a C-style comment
- set start [pos::math [lindex [search -s -f 0 -r 1 "^\[ \t\]*(${chreg}+|/\\*+)\[ \t\]*\$" $pos] 1] +1]
- set end [lindex [search -s -f 1 -r 1 "^\[ \t\]*(${chreg}+|\\*+/)\[ \t\]*\$" $pos] 0]
- } else {
- set start [lindex [search -s -n -f 0 -r 1 "^\[ \t\]*(${chreg}+\[ \t\]*${chreg}*\$|\[^${chreg} \t\]|\$)" $pos] 0]
- set end [lindex [search -s -n -f 1 -r 1 "^\[ \t\]*(${chreg}+\[ \t\]*${chreg}*\$|\[^${chreg} \t\]|\$)" $pos] 0]
- # The comment doesn't have a leading/trailing almost blank line
- # Look for any line which is either blank, or starts with a
- # different character
- if {$start == ""} {
- set start [nextLineStart [lindex [search -s -f 0 -r 1 "^\[ \t\]*(\[^ \t[string index $ch 0]\]|\$)" $pos] 0]]
- } else {
- set start [nextLineStart $start]
- }
- if {$end == ""} {
- set end [lindex [search -s -f 1 -r 1 "^\[ \t\]*(\[^ \t[string index $ch 0]\]|\$)" $pos] 0]
- }
- }
- } else {
- set start [paraStart $pos]
- if {[pos::compare $start > $pos]} {
- set end [paraFinish $start]
- } else {
- set end [paraFinish $pos]
- }
- }
- # Extra arguments allow us to specify a region in which to operate
- if {$minstart != ""} {
- if {[pos::compare $minstart > $start]} {
- set start $minstart
- }
- }
- if {$maxend != ""} {
- if {[pos::compare $maxend < $end]} {
- set end $maxend
- }
- }
-
- if {$remember} {
- if {$inComment} {
- set memory [rememberWhereYouAre $start $pos $end $chreg]
- } else {
- set memory [rememberWhereYouAre $start $pos $end]
- }
- }
-
- if {$inComment} {
- set text [getText $start [nextLineStart $start]]
- if {[set boxComment [regexp -- "(${chreg}+)\[\r\n\]" $text "" commentSuffix]]} {
- set boxWidth [posX [pos::math [nextLineStart $start] -1]]
- }
- regsub -all -- $chreg $text [string range " " 1 [string length $ch]] fr
- regexp "^\[ \t\]*" $fr fr
- set left [string length [text::maxSpaceForm $fr]]
- if {$boxComment} {
- set newFillColumn [expr {$boxWidth - $left - [string length $commentSuffix] -2}]
- } else {
- set newFillColumn [expr {$fillColumn - $left}]
- }
-
- if {![regexp "^((\[ \t\]*${chreg}+)\[ \t\]*)" $text "" front commentPrefix]} {
- alertnote "Sorry, I can't yet reflow the text inside this comment."
- return $end
- }
- if {$boxComment} {
- regsub -all "[quote::Regfind $commentSuffix](\r|\n|$)" [getText $start $end] "\\1" text
- regsub -all "(^|\r|\n)[quote::Regfind $commentPrefix]" $text "" text
- } else {
- regsub -all "(^|\r|\n)[quote::Regfind $commentPrefix]" [getText $start $end] "" text
- }
-
- regsub -all "\[ \t\r\n\]+" [string trim $text] " " text
- } else {
- # Get the leading whitespace of the current line and store length in 'left'
- set front [getLeadingIndent $pos left]
- # fill the text
- regsub -all "\[ \t\r\n\]+" [string trim [getText $start $end]] " " text
- set newFillColumn [expr {$fillColumn - $left}]
- }
-
- # turn single spaces at end of sentences into double
- if {$doubleSpaces} {regsub -all {(([^.][a-z]|[^a-zA-Z@]|\\@)[.?!]("|'|'')?([])])?) } $text {\1 } text}
- # if {$doubleSpaces} {regsub -all {(([^A-Z@]|\\@)[.?!][])'"]?) } $text {\1 } text}
-
- # temporarily adjust the fillColumns
- set ol $leftFillColumn
- set or $fillColumn
- set leftFillColumn 0
- set fillColumn $newFillColumn
-
- # break and indent the paragraph
- regsub -all " ?\r" "\r[string trimright [breakIntoLines $text]]" "\r${front}" text
- # reset columns
- set leftFillColumn $ol
- set fillColumn $or
- if {$inComment && $boxComment} {
- global bind::_IndentSpaces
- set newtext ""
- foreach line [split $text "\r\n"] {
- puts stdout [string length $line]
- set pad [string range [set bind::_IndentSpaces] 0 [expr {$boxWidth- [string length $line] -2}]]
- lappend newtext "$line$pad$commentSuffix"
- }
- set text "\r[join [lrange $newtext 1 end] \r]"
- }
-
- # don't replace if nothing's changed
- if {"$text\r" != "\r[getText $start $end]"} {
- # workaround an alpha bug
- if {$remember} {
- getWinInfo a
- if {[pos::compare [rowColToPos $a(currline) 0] > $start]} { goto $start }
- }
- replaceText $start $end "[string range $text 1 end]\r"
- if {$remember} {
- goBackToWhereYouWere $start [pos::math $start + \
- [string length $text]] $memory
- }
- }
-
- # in case we wish to fill a region
- return $end
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "paraStart" -- "paraFinish"
- #
- # Newly simplified version with fewer regexp '()' pairs. Also I think it
- # deals better with TeX comments than the old regexp.
- #
- # "Start": It's pretty clear for non TeX modes how this works. The only
- # key is that we start at the beginning of the current line and look
- # back. We then have a quick check for whether we found that very
- # beginning (in which case return it) or if not (in which case we have
- # found the end of the previous paragraph) we move forward a line.
- #
- # "Finish": The only addition is the need for an additional check for
- # stuff which explicitly ends lines.
- #
- # Results:
- # The start/finish position of the paragraph containing the given 'pos'
- #
- # --Version--Author------------------Changes-------------------------------
- # 1.1 <darley@fas.harvard.edu> Cut down on '()' pairs
- # 1.2 Vince - March '96 Better filling for TeX tables ('hline')
- # 1.3 Johan Linde - May '96 Now sensitive to HTML elements
- # 1.4 <darley@fas.harvard.edu> Handle Tcl lists, top of file fix.
- # -------------------------------------------------------------------------
- ##
- proc paraStart {pos} {
- global mode
- global ${mode}::startPara
- if {[pos::compare $pos == [maxPos]]} {set pos [pos::math $pos - 1]}
- set pos [lineStart $pos]
- if {[info exists ${mode}::startPara]} {
- set startPara [set ${mode}::startPara]
- } else {
- switch -- $mode {
- "TeX" -
- "Bib" {
- global texParaCommands
- set startPara {^[ \t]*$|\\\\[ \t]*$|(^|[^\\])%|\\h+line[ \t]*$|\$\$[ \t]*$|^[ \t]*(\\(}
- append startPara $texParaCommands {)(\[.*\]|\{.*\}|•)*[ \t]*)+$}
- }
- "HTML" {
- global htmlParaCommands
- set startPara {^[ \t]*$|</?(}
- append startPara $htmlParaCommands {)([ \t\r]+[^>]*>|>)}
- }
- default {
- set startPara {^([ \t]*|([\\%].*))$}
- }
- }
- }
-
- set res [search -s -n -f 0 -r 1 -l [minPos] -- "$startPara" $pos]
- if {![llength $res] || $res == "0 0" } {
- # bug work-around. Alpha fails to match '^' with start of file.
- return [lineStart [lindex [search -s -f 1 -r 1 "\[^ \t\r\n\]" [minPos]] 0]]
- } elseif {[pos::compare [lindex $res 0] == $pos]} {
- return $pos
- } else {
- return [nextLineStart [lindex $res 0]]
- }
-
- }
-
- proc paraFinish {pos} {
- global mode
- global ${mode}::endPara
- set pos [lineStart $pos]
- set end [maxPos]
- if {[info exists ${mode}::endPara]} {
- set endPara [set ${mode}::endPara]
- } else {
- switch -- $mode {
- "TeX" -
- "Bib" {
- global texParaCommands
- set endPara {^[ \t]*$|(^|[^\\])%|\$\$[ \t]*$|^[ \t]*(\\(}
- append endPara $texParaCommands {)(\[.*\]|\{.*\}|•)*[ \t]*)+$}
- }
- "HTML" {
- global htmlParaCommands
- set endPara {^[ \t]*$|</?(}
- append endPara $htmlParaCommands {)([ \t\r\n]+[^>]*>|>)}
- }
- default {
- set endPara {^([ \t]*|([\\%].*))$}
- }
- }
- }
-
- set res [search -s -n -f 1 -r 1 -l $end -- "$endPara" $pos]
- if {![string length $res]} {return $end}
- set cpos [lineStart [lindex $res 0]]
- if {[pos::compare $cpos == $pos]} {
- return [nextLineStart $cpos]
- }
- # A line which ends in '\\', '%...', '\hline', '\hhline'
- # signifies the end of the current paragraph in TeX mode
- # (the above checked for beginning of the next paragraph).
- if { $mode == "TeX" || $mode == "Bib" } {
- set res2 [search -s -n -f 1 -r 1 -l $end {((\\\\|\\h+line)[ \t]*|[^\\]%.*)$} $pos]
- if {[string length $res2]} {
- if {[pos::compare [lindex $res2 0] < $cpos] } {
- return [nextLineStart [lindex $res2 0]]
- }
- }
- }
-
- return $cpos
-
- }
-
- proc selectParagraph {} {
- set pos [getPos]
- set start [paraStart $pos]
- set finish [paraFinish $pos]
- goto $start
- select $start $finish
- }
-
- proc sentenceParagraph {} {
- set pos [getPos]
- set start [paraStart $pos]
- set finish [paraFinish $pos]
-
- set t [string trim [getText $start $finish]]
- set period [regexp {\.$} $t]
- regsub -all "\[ \t\r\n\]+" $t " " text
- regsub -all {\. } $text "Δ" text
- set result ""
- foreach line [split [string trimright $text {.}] "Δ"] {
- if {[string length $line]} {
- append result [breakIntoLines $line] ".\r"
- }
- }
- if {!$period && [regexp {\.\r} $result]} {
- set result [string trimright $result ".\r"]
- append result "\r"
- }
- if {$result != [getText $start $finish]} {
- replaceText $start $finish $result
- }
- goto $pos
- }
-
- proc getEndpts {} {
- if {[pos::compare [getPos] == [selEnd]]} {
- set start [getPos]
- set finish [getMark]
- if {[pos::compare $start > $finish]} {
- set temp $start
- set start $finish
- set finish $temp
- }
- } else {
- set start [getPos]
- set finish [selEnd]
- }
- return [list $start $finish]
- }
-
-
- proc fillRegion {} {
- global leftFillColumn
- set ends [getEndpts]
- set start [lineStart [lindex $ends 0]]
- set finish [lindex $ends 1]
- goto $start
- set text [fillText $start $finish]
- replaceText $start $finish [format "%$leftFillColumn\s" ""] $text "\r"
- }
-
- proc wrapParagraph {} {
- set pos [getPos]
- set start [paraStart $pos]
- set finish [paraFinish $pos]
- goto $start
- wrapText $start $finish
- goto $pos
- }
-
- proc wrapRegion {} {
- set ends [getEndpts]
- set start [lineStart [lindex $ends 0]]
- set finish [lindex $ends 1]
- if {[pos::compare $start == $finish]} {
- set finish [maxPos]
- }
- wrapText $start $finish
- }
-
-
-
- # Remove text from window, transform, and insert back into window.
- proc fillText {from to} {
- global doubleSpaces
- set text [getText $from $to]
- regexp "^\[ \t\]*" $text front
- regsub -all "\[ \t\n\r\]+" [string trim $text] " " text
- if {$doubleSpaces} {regsub -all {(([^.][a-z]|[^a-zA-Z@]|\\@)[.?!]("|'|'')?([])])?) } $text {\1 } text}
- regsub -all " ?\[\r\n\]" [string trimright [breakIntoLines $text]] "\r${front}" text
- return $front$text
- }
-
- proc paragraphToLine {} {
- global fillColumn
- global leftFillColumn
- set fc $fillColumn
- set lc $leftFillColumn
- set fillColumn 10000
- set leftFillColumn 0
- fillRegion
- set fillColumn $fc
- set leftFillColumn $lc
- }
-
- proc lineToParagraph {} {
- global fillColumn
- global leftFillColumn
- set fc $fillColumn
- set fillColumn 75
- set lc $leftFillColumn
- set leftFillColumn 0
- fillRegion
- set fillColumn $fc
- set leftFillColumn $lc
- }
-
-
- #set sentEnd {[.!?](\r|\n| +)}
- set sentEnd {(\r\r|\n\n|[.!?](\r|\n| +))}
- set sentBeg {[\r\n ][A-Z]}
-
- proc nextSentence {} {
- global sentBeg sentEnd
- if {![catch {search -s -f 1 -r 1 $sentEnd [getPos]} mtch]} {
- if {![catch {search -s -f 1 -r 1 -i 0 $sentBeg [pos::math [lindex $mtch 1] - 1]} mtch]} {
- goto [pos::math [lindex $mtch 0] + 1]
- }
- }
- }
-
-
- proc prevSentence {} {
- global sentBeg sentEnd
- if {[catch {search -s -f 0 -r 1 $sentBeg [pos::math [getPos] - 2]} mtch]} return
- if {![catch {search -s -f 0 -r 1 $sentEnd [lindex $mtch 1]} mtch]} {
- if {![catch {search -s -f 1 -r 1 -i 0 $sentBeg [pos::math [lindex $mtch 1] - 1]} mtch]} {
- goto [pos::math [lindex $mtch 0] + 1]
- }
- }
- }
-
- #===============================================================================
- # Called by Alpha to do "soft wrapping"
- proc softProc {pos start next} {
- global leftFillColumn
- goto $start
- set finish [paraFinish $start]
- set text [fillText $start $finish]
- if {"${text}\r" != [getText $start $finish]} {
- replaceText $start $finish [format "%$leftFillColumn\s" ""] $text "\r"
- return 1
- } else {
- return 0
- }
- }
-
- proc dividingLine {} {
- global mode
- global ${mode}modeVars
- if {[info exists ${mode}modeVars(prefixString)]} {
- set a [string trim [set ${mode}modeVars(prefixString)]]
- } else {
- set a "#"
- }
- insertText "${a}===============================================================================\r"
- }
-